/**
 * 是否数组
 */
function isArray(value) {
    if (typeof Array.isArray === 'function') {
        return Array.isArray(value);
    }
    return Object.prototype.toString.call(value) === '[object Array]';
}

/**
 * @description 深度克隆
 * @param {object} obj 需要深度克隆的对象
 * @returns {*} 克隆后的对象或者原值（不是对象）
 */
function deepClone(obj) {
    // 对常见的“非”值，直接返回原来值
    if ([null, undefined, NaN, false].includes(obj)) return obj;
    if (typeof obj !== 'object' && typeof obj !== 'function') {
        // 原始类型直接返回
        return obj;
    }
    const o = isArray(obj) ? [] : {};
    for (const i in obj) {
        if (obj.hasOwnProperty(i)) {
            o[i] = typeof obj[i] === 'object' ? deepClone(obj[i]) : obj[i];
        }
    }
    return o;
}

/**
 * @description JS对象深度合并
 * @param {object} target 需要拷贝的对象
 * @param {object} source 拷贝的来源对象
 * @returns {object|boolean} 深度合并后的对象或者false（入参有不是对象）
 */
export function deepMerge(target = {}, source = {}) {
    target = deepClone(target);
    if (typeof target !== 'object' || typeof source !== 'object') return false;
    for (const prop in source) {
        if (!source.hasOwnProperty(prop)) continue;
        if (prop in target) {
            if (typeof target[prop] !== 'object') {
                target[prop] = source[prop];
            } else if (typeof source[prop] !== 'object') {
                target[prop] = source[prop];
            } else if (target[prop].concat && source[prop].concat) {
                target[prop] = target[prop].concat(source[prop]);
            } else {
                target[prop] = deepMerge(target[prop], source[prop]);
            }
        } else {
            target[prop] = source[prop];
        }
    }
    return target;
}

export const typeMap = {
    INPUT: 'input',
    INPUT_NUMBER: 'inputNumber',
    TEXTAREA: 'textarea',
    NUMBER: 'number',
    CHOOSE: 'choose',
    DATE: 'date',
    DATETIME: 'datetime',
    TIME: 'time',
    AREA: 'area',
};
export const perMap = {
    [typeMap.INPUT]: '请输入',
    [typeMap.INPUT_NUMBER]: '请输入',
    [typeMap.TEXTAREA]: '请输入',
    [typeMap.NUMBER]: '请填写',
    [typeMap.CHOOSE]: '请选择',
    [typeMap.DATE]: '请选择',
    [typeMap.DATETIME]: '请选择',
    [typeMap.TIME]: '请选择',
    [typeMap.AREA]: '请选择',
};

const defaultConfig = {
    // formItem 属性
    itemAttrs: {},
    // formItem 中内容属性
    elAttrs: {},
    // 校验规则
    rule: {},
    // 标签追加字符串
    labelSuffix: '',
    // 是否将 rule 放到 formItem 上
    isItemRule: true,
};

/**
 * form 快速生成
 * ---
 * <p>
 * elAttrs 具有的额外属性
 * - textareaAlign 文本域对齐方式
 * - formatter 格式化显示内容
 * - resourceIdField 上传文件的资源主键属性
 * </p>
 * ---
 * <p>
 * itemAttrs 具有的额外属性
 * - labelPosition 自定义 label 时 label 的位置，同时也是每个 item 的单独的属性
 * </p>
 * ---
 * @param {{
 *   label?: string,
 *   type?: typeMap[keyof typeMap],
 *   prop: string,
 *   required?: boolean,
 *   customLabel?: boolean,
 *   elAttrs?: {
 *     textareaAlign?: 'left' | 'right',
 *     numberAlign?: 'left' | 'right',
 *     formatter?: Function,
 *     resourceIdField?: string
 *   } | Object,
 *   itemAttrs?: {
 *     labelPosition: 'top' | 'left'
 *   } | Object,
 *   rule?: Object | Object[],
 *   showRender?: Function,
 *   itemAttrsRender?: Function,
 *   elAttrsRender?: Function,
 *   valueRender?: Function
 * }[]|{
 *   label?: string,
 *   type?: typeMap[keyof typeMap],
 *   prop: string,
 *   required?: boolean,
 *   customLabel?: boolean,
 *   elAttrs?: {
 *     textareaAlign?: 'left' | 'right',
 *     numberAlign?: 'left' | 'right',
 *     formatter?: Function,
 *     resourceIdField?: string
 *   } | Object,
 *   itemAttrs?: {
 *     labelPosition: 'top' | 'left'
 *   } | Object,
 *   rule?: Object | Object[],
 *   showRender?: Function,
 *   itemAttrsRender?: Function,
 *   elAttrsRender?: Function,
 *   valueRender?: Function
 * }[][]} items form 项
 * @param {{
 *   itemAttrs?: Object,
 *   elAttrs?: Object,
 *   rule?: Object,
 *   labelSuffix?: string,
 *   isItemRule?: boolean,
 * }} [config] 配置
 * @return {{formRules: *, itemList: *}}
 */
export function useForm(items, config) {
    const startTime = Date.now();

    const props = Object.assign({}, defaultConfig, config || {});

    const itemList = (items || []).map(item => relItem(item));
    const formRules = getFormRules();

    function relItem(item) {
        if (item instanceof Array) {
            return item.map(item => relItem(item));
        }
        const itemNew = deepClone(item);
        itemNew.originLabel = itemNew.label;
        itemNew.label = itemNew.originLabel + props.labelSuffix;
        if (!itemNew.type) itemNew.type = typeMap.INPUT;
        const itemAttrs = deepClone(props.itemAttrs || {});
        itemNew.itemAttrs = deepMerge(itemAttrs, itemNew.itemAttrs);
        itemNew.itemAttrs.required = itemNew.itemAttrs.required || (itemNew.required || false);
        const elAttrs = deepClone(props.elAttrs);
        itemNew.elAttrs = deepMerge(elAttrs, itemNew.elAttrs);
        itemNew.elAttrs.placeholder = relPlaceholder(itemNew);
        return itemNew;
    }

    function getFormRules() {
        const rules = {};
        itemList.forEach((item) => {
            doGetFormRules(item, rules);
        });
        return rules;
    }

    function doGetFormRules(item, rules) {
        if (item instanceof Array) {
            item.forEach(item => {
                doGetFormRules(item, rules);
            });
        }
        let rule = {};
        if (item.itemAttrs && item.itemAttrs.required) {
            let type = 'string';
            if ([typeMap.INPUT_NUMBER, typeMap.NUMBER].includes(item.type)) {
                // 数字类型
                type = 'number';
            }
            rule = {
                type,
                required: true,
                message: relPlaceholder(item),
                trigger: ['blur', 'change'],
            };
        }
        if (item.rule) {
            if (item.rule instanceof Array) {
                rule = item.rule;
            } else if (typeof item.rule === 'object') {
                let propsRule = {};
                if (props.rule && Object.keys(item.rule).length > 0) {
                    propsRule = props.rule;
                }
                rule = deepMerge(rule, propsRule);
                rule = deepMerge(rule, item.rule);
            }
        }
        rules[item.prop] = rule;
    }

    function relPlaceholder(item) {
        const elAttrs = item.elAttrs;
        if (elAttrs.placeholder || elAttrs.placeholder === '') return elAttrs.placeholder;
        const perStr = perMap[item.type];
        if (perStr) {
            return perStr + item.originLabel;
        }
        return '';
    }

    // 将 rule 添加到 itemAttrs 中
    function setRuleToItem(items, ruleKeys) {
        if (items instanceof Array) {
            for (let item of items) {
                setRuleToItem(item, ruleKeys);
            }
        } else if (ruleKeys.includes(items.prop)) {
            const rule = formRules[items.prop];
            if (!items.itemAttrs) {
                items.itemAttrs = {};
            }
            if (rule instanceof Array) {
                items.itemAttrs.rules = rule;
            } else if (typeof rule === 'object') {
                items.itemAttrs.rules = [rule];
            }
        }
    }

    // 开启 formItem rule 时，将 rule 放到 item 中
    if (props.isItemRule) {
        const ruleKeys = Object.keys(formRules);
        for (let item of itemList) {
            setRuleToItem(item, ruleKeys);
        }
    }

    // // 将最后一个 formItem 下边框设置为 false
    // function setLastItemBottomBorderHide(items) {
    //   if (!items || items.length === 0) return;
    //   for (let i = 1; i <= items.length; i++) {
    //     if (i === items.length) {
    //       const item = items[i - 1];
    //       if (item) {
    //         if (!item.itemAttrs) {
    //           item.itemAttrs = {};
    //         }
    //         item.itemAttrs.borderBottom = false;
    //       }
    //     }
    //   }
    // }
    //
    // // 隐藏最后一个 formItem 下边框处理
    // if (props.hideLastItemBottomBorder) {
    //   if (itemList instanceof Array) {
    //     for (let items of itemList) {
    //       setLastItemBottomBorderHide(items);
    //     }
    //   } else {
    //     setLastItemBottomBorderHide(itemList);
    //   }
    // }

    console.log('useForm 处理完毕，耗时：', ((Date.now() - startTime) / 1000).toFixed(4) + '秒');

    return {
        itemList,
        formRules,
    };
}

export const commonFormStyleConfig = {
    elAttrs: {
        border: 'none',
        inputAlign: 'right',
        clearable: true,
        textareaAlign: 'right',
        numberAlign: 'right',
    },
    labelSuffix: ':',
    itemAttrs: { borderBottom: true, labelWidth: 'auto' },
};

/**
 * 传入表单 ref 校验表单
 * @param form 表单 ref
 * @return {Promise<void>}
 */
export async function validateForm(form) {
    await form.validate();
}

/**
 * 传入表单 ref 和字段名，校验指定字段
 * @param form 表单 ref
 * @param {...string} fields 字段名，可多个
 */
export function validateFields(form, ...fields) {
    for (let field of fields) {
        form.validateField(field);
    }
}

/**
 * 传入配置合并默认的配置
 * @param {{
 *   itemAttrs?: Object,
 *   elAttrs?: Object,
 *   rule?: Object,
 *   labelSuffix?: string,
 *   isItemRule?: boolean,
 * }} [config] 配置
 * @return {{elAttrs: {border: string, clearable: boolean, inputAlign: string, numberAlign: string, textareaAlign: string}, itemAttrs: {labelWidth: string, borderBottom: boolean}, labelSuffix: string}|Object}
 */
export function commonFormStyleConfigMerge(config) {
    let commonConfig = deepMerge({}, commonFormStyleConfig);
    if (commonConfig) {
        commonConfig = deepMerge(commonConfig, config);
    }
    if (commonConfig) {
        return commonConfig;
    }
    return commonFormStyleConfig;
}

